package org.tinycloud.tinyjob.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *   执行器配置类
 * </p>
 *
 * @author liuxingyu01
 * @since 2025/9/27 22:18
 */
public class TinyJobExecutorConfig {
    private static final Logger logger = LoggerFactory.getLogger(TinyJobExecutorConfig.class);

    // 调度中心部署根地址 [选填]：如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调"；为空则关闭自动注册；
    private String adminAddresses;

    // 调度中心安全通讯TOKEN [选填]：非空时启用；
    private String accessToken;

    // 调度中心链接超时时间[选填]，单位秒；默认3s；
    private Integer connectTimeout;

    // 调度中心通讯超时时间[选填]，单位秒；默认10s；
    private Integer socketTimeout;

    // 项目ID [选填]：项目ID；为空则关闭自动注册；
    private Long projectId;

    // 执行节点标识 [选填]：执行器心跳注册分组依据；为空则关闭自动注册；
    private String workerName;

    //  执行器注册 [选填]：优先使用该配置作为注册地址，为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
    private String address;

    // 执行器IP [选填]：默认为空表示自动获取IP，多网卡时可手动设置指定IP，该IP不会绑定Host仅作为通讯使用；地址信息用于 "执行器注册" 和 "调度中心请求并触发任务"；
    private String ip;

    // 执行器端口号 [选填]：小于等于0则自动获取；默认端口为9999，单机部署多个执行器时，注意要配置不同执行器端口；
    private Integer port;

    public String getAdminAddresses() {
        return adminAddresses;
    }

    public void setAdminAddresses(String adminAddresses) {
        this.adminAddresses = adminAddresses;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public Integer getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(Integer connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public Integer getSocketTimeout() {
        return socketTimeout;
    }

    public void setSocketTimeout(Integer socketTimeout) {
        this.socketTimeout = socketTimeout;
    }

    public String getWorkerName() {
        return workerName;
    }

    public void setWorkerName(String workerName) {
        this.workerName = workerName;
    }

    public Long getProjectId() {
        return projectId;
    }

    public void setProjectId(Long projectId) {
        this.projectId = projectId;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }


    /**
     * 用于定时执行数据清理的线程池
     */
    private volatile ScheduledExecutorService executorService;

    public void start() {
        // 开始注册
        TinyJobHelper.register(this);
        // 开始心跳线程
        this.initHeartbeatThread();
    }

    public void destroy() {
        // 停止心跳线程
        if (executorService != null) {
            // 优雅关闭：等待当前任务完成，不再执行下一次
            executorService.shutdown();
            try {
                // 等待一段时间让任务优雅终止，超时则强制关闭
                if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                    // 超时后强制关闭剩余任务
                    executorService.shutdownNow();
                    logger.info("TinyJob heartbeat executor forced shutdown");
                } else {
                    logger.info("TinyJob heartbeat executor closed gracefully");
                }
            } catch (InterruptedException e) {
                // 等待过程中被中断，强制关闭
                executorService.shutdownNow();
                logger.error("TinyJob heartbeat executor shutdown interrupted", e);
            }
            // 清空引用，避免重复关闭
            executorService = null;
        }
    }

    /**
     * 初始化心跳线程，默认20s执行一次
     */
    private void initHeartbeatThread() {
        // 双重校验构造一个单例的ScheduledThreadPool
        if (this.executorService == null) {
            synchronized (TinyJobExecutorConfig.class) {
                if (this.executorService == null) {
                    this.executorService = Executors.newScheduledThreadPool(1);
                    this.executorService.scheduleAtFixedRate(() -> {
                        logger.info("TinyJob heartbeat execute at: {}", LocalDateTime.now());
                        try {
                            // 执行清理方法
                            TinyJobHelper.heartbeat(this);
                        } catch (Exception e2) {
                            logger.error("TinyJob heartbeat Exception: {e2}", e2);
                        }
                    }, 20 * 1000/*首次延迟多长时间后执行*/, 20 * 1000/*定时任务间隔时间，这里设置的是20秒*/, TimeUnit.MILLISECONDS);
                }
            }
        }
        logger.info("TinyJob heartbeat successful!");
    }
}
